#include "stdafx.h"
#include <cstdlib>
#include <conio.h>
#include <atlbase.h>
#include <iostream>
#include <wlanapi.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>

#pragma comment(lib, "Ws2_32.lib")


DWORD dClientVersion, dNegotiatedVersion;
HANDLE hClientHandle;
PWLAN_INTERFACE_INFO_LIST pInterfaceList;
DWORD dSelectedInterfaceIndex;
PWLAN_CONNECTION_ATTRIBUTES pCurrentConnInfo;
DWORD	dwSize;

INT iReqestedOp, iContinue;

/**
* Select a network interface function that uses WLAN API
* to get the wireless interface list.
*/
DWORD SelectNetworkInterface()
{
	DWORD rtn;

	dClientVersion = 1;
	dNegotiatedVersion = 0;
	rtn = WlanOpenHandle(dClientVersion, NULL, &dNegotiatedVersion, &hClientHandle);
	if(rtn != ERROR_SUCCESS)
	{
		_tprintf("Error occured in WlanOpenHandle: %d\n", rtn);
		return rtn;
	}

	pInterfaceList = NULL;
	rtn = WlanEnumInterfaces(hClientHandle, NULL, &pInterfaceList);
	if(rtn != ERROR_SUCCESS)
	{
		_tprintf("Error occured in WlanEnumInterfaces: %d\n", rtn);
		return rtn;
	}

	
	_tprintf("List of WLAN Interfaces\n");

	for(pInterfaceList->dwIndex = 0; pInterfaceList->dwIndex < pInterfaceList->dwNumberOfItems; pInterfaceList->dwIndex++)
	{
		CW2T szIfcName(pInterfaceList->InterfaceInfo[pInterfaceList->dwIndex].strInterfaceDescription);
		_tprintf("%2d - %s\n", (pInterfaceList->dwIndex + 1), szIfcName);
	}

	dSelectedInterfaceIndex = 11000;
	while(dSelectedInterfaceIndex < 1 || dSelectedInterfaceIndex > pInterfaceList->dwNumberOfItems)
	{
		fflush(stdin);
		dSelectedInterfaceIndex = 11000;
		_tprintf("\n");
		_tprintf("Select the interface by typing the number and pressing enter - ");
		_tscanf_s("%d", &dSelectedInterfaceIndex);
	}
	
	//dSelectedInterfaceIndex = 1;
	pInterfaceList->dwIndex = dSelectedInterfaceIndex - 1;

	return rtn;
}


/**
* Issue a scan to find the visible APs using the NDIS 802.11 IOCTL.
* 
* Note: This function doesn't seem to be working. I will have to figure
*       this out, later.
*/
DWORD ScanwithNDIS()
{
	INT rtn;
	WCHAR	wsNICGUIDinString[256];
	char	sNICIDFullPath[256];
	DWORD	dwMemSize;
	ULONG	ulBytesReturned;
	ULONG	ulOIDCode;

	// open handle
	memset(wsNICGUIDinString, 0, 256);
	memset(sNICIDFullPath, 0, 256);
	StringFromGUID2(pInterfaceList->InterfaceInfo[pInterfaceList->dwIndex].InterfaceGuid, 
						wsNICGUIDinString, 256);
	sprintf_s(sNICIDFullPath, "\\\\.\\%S", wsNICGUIDinString);
	//hClientHandle = CreateFileA(sNICIDFullPath, GENERIC_READ | GENERIC_WRITE, 
	//										FILE_SHARE_READ | FILE_SHARE_WRITE,
	//										NULL, OPEN_EXISTING,
	//										0, NULL) ;
	hClientHandle = CreateFileA(sNICIDFullPath, GENERIC_READ, 
											FILE_SHARE_READ | FILE_SHARE_WRITE,
											NULL, OPEN_EXISTING,
											0, NULL) ;

	if(hClientHandle == INVALID_HANDLE_VALUE)
	{
		_tprintf("Error in CreateFileA\n");
		return 0;
	}

	// call to get connected ESSID
	dwMemSize = 0;
	ulOIDCode = OID_802_11_BSSID_LIST_SCAN;
	ulOIDCode |= 0x00800000;
	ulBytesReturned = 0;
	rtn = DeviceIoControl(hClientHandle, IOCTL_NDIS_QUERY_GLOBAL_STATS,
							&ulOIDCode, sizeof(ulOIDCode), (ULONG *) NULL,
							dwMemSize, &ulBytesReturned, NULL);
	if(rtn == 0)
	{
			DWORD errnum = GetLastError();
		_tprintf("Error in DeviceIoControl\n");
		CloseHandle(hClientHandle);
		return rtn;
	}

	// close handle
	CloseHandle(hClientHandle);

	_tprintf("Scan issued...\n");

	//_tprintf("\n\n");
	//_tprintf("Type 99 to continue ... ");
	//_tscanf_s("%d", &iContinue);

	return rtn;
}


char* ShowNetworkListwithNDIS()
{
	INT		rtn;
	WCHAR	wsNICGUIDinString[256];
	char	sNICIDFullPath[256];
	DWORD	dwMemSize;
	ULONG	ulBytesReturned;
	ULONG	ulOIDCode;
	PNDIS_802_11_BSSID_LIST pNDIS80211BSSIDList;
	PNDIS_WLAN_BSSID pNDIS80211BSSIDInfo;
	TCHAR szESSIDStr1[256];
	TCHAR szMACAddressStr[256];
	UINT i, j;

	char Result[1024];
	strcpy_s(Result, "");
	// open handle
	memset(wsNICGUIDinString, 0, 256);
	memset(sNICIDFullPath, 0, 256);
	StringFromGUID2(pInterfaceList->InterfaceInfo[pInterfaceList->dwIndex].InterfaceGuid, 
						wsNICGUIDinString, 256);
	sprintf_s(sNICIDFullPath, "\\\\.\\%S", wsNICGUIDinString);
	hClientHandle = CreateFileA(sNICIDFullPath, GENERIC_READ, 
											FILE_SHARE_READ | FILE_SHARE_WRITE,
											NULL, OPEN_EXISTING,
											0, NULL) ;

	if(hClientHandle == INVALID_HANDLE_VALUE)
	{
		_tprintf("Error in CreateFileA\n");
		return 0;
	}

	// allocate temporary memory to check the number of
	// AP entries
	dwMemSize = sizeof(NDIS_802_11_BSSID_LIST) + (sizeof(NDIS_WLAN_BSSID) * 24);
	pNDIS80211BSSIDList = (NDIS_802_11_BSSID_LIST *) VirtualAlloc(NULL,
									dwMemSize, MEM_RESERVE | MEM_COMMIT,
									PAGE_READWRITE);
	memset(pNDIS80211BSSIDList, 0, dwMemSize);
	
	// set OID
	ulOIDCode = OID_802_11_BSSID_LIST;
	ulBytesReturned = 0;

	// call get AP list
	rtn = DeviceIoControl(hClientHandle, IOCTL_NDIS_QUERY_GLOBAL_STATS,
							&ulOIDCode, sizeof(ulOIDCode), (ULONG *) pNDIS80211BSSIDList,
							dwMemSize, &ulBytesReturned, NULL);
	if(!(rtn != 0 || (rtn == 0 && GetLastError() == ERROR_MORE_DATA)))
	{
		_tprintf("Error occured in DeviceIoControl OID_802_11_BSSID_LIST: %d\n", rtn);
		// free memory allocation
		VirtualFree(pNDIS80211BSSIDList, dwMemSize,	MEM_RELEASE | MEM_DECOMMIT);
		CloseHandle(hClientHandle);
		return Result;
	}

	_tprintf("\n");
	_tprintf("    SSID (Network)       MAC Address       RSSI \n");
	// loop and print
	for(i = 0; i < pNDIS80211BSSIDList->NumberOfItems; i++)
	{

		// find the location of next element
		j = 0;
		pNDIS80211BSSIDInfo = pNDIS80211BSSIDList->Bssid;
		while(j < i)
		{
			pNDIS80211BSSIDInfo = (PNDIS_WLAN_BSSID) (((unsigned char *) pNDIS80211BSSIDInfo)
								+ pNDIS80211BSSIDInfo->Length);
			j++;
		}

		memset(szESSIDStr1, 0, 256);
		memcpy(szESSIDStr1, pNDIS80211BSSIDInfo->Ssid.Ssid, pNDIS80211BSSIDInfo->Ssid.SsidLength);
		_tprintf("%24s ", szESSIDStr1);

		memset(szMACAddressStr, 0, 256);
		_stprintf_s(szMACAddressStr, 256, "%02x:%02x:%02x:%02x:%02x:%02x", 
			pNDIS80211BSSIDInfo->MacAddress[0],
			pNDIS80211BSSIDInfo->MacAddress[1],
			pNDIS80211BSSIDInfo->MacAddress[2],
			pNDIS80211BSSIDInfo->MacAddress[3],
			pNDIS80211BSSIDInfo->MacAddress[4],
			pNDIS80211BSSIDInfo->MacAddress[5]);
		_tprintf("%s ", szMACAddressStr);
		_tprintf("%4d ", pNDIS80211BSSIDInfo->Rssi);
		_tprintf("\n");
		
		char rssi[4];
		itoa(pNDIS80211BSSIDInfo->Rssi, rssi, 10);
		// (strcmp(szESSIDStr1, "NETGEAR"))
		{
			// strcat(Result, szESSIDStr1);
			// strcat(Result, ",");
			strcat(Result, szMACAddressStr);
			strcat(Result, ",");
			strcat(Result, rssi);
			strcat(Result, ";");
		}
		//strcat(Result)
	}

	VirtualFree(pNDIS80211BSSIDList, dwMemSize,	MEM_RELEASE | MEM_DECOMMIT);
	// close handle
	CloseHandle(hClientHandle);

	return Result;
}


int _tmain(int argc, _TCHAR* argv[])
{
	/* SOCKET */
	WSADATA data;
	WSAStartup( MAKEWORD(2,2), &data);  

	SOCKADDR_IN dest; 
	dest.sin_family = AF_INET;
	dest.sin_port = htons(8000);
	dest.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 

	SOCKET s = socket(AF_INET,SOCK_DGRAM,0);    

	DWORD rtn;
	rtn = SelectNetworkInterface();

	do
	{	
		if(rtn == ERROR_SUCCESS)
		{
			ScanwithNDIS();
			_tprintf("waiting 3 seconds");
			Sleep(5000);
			_tprintf("break");

			char* r = ShowNetworkListwithNDIS();
			char* sendBuf = r;
			sendto(s,sendBuf,strlen(sendBuf)+1,0,(sockaddr*)&dest, sizeof(dest));  
		}
	} 
	while(iReqestedOp != 99);
	return 0;
}